unit Utils;

{*
Various utility functions, string to array conversion routines, command line argument parsing
}

interface

{$I configs.inc}

uses SysUtils, Classes, StrUtils;

type TArrayOfString = array of string; //* auxiliary array of strings

// string to array conversion routines
function StrToArray(AData,ASeparator : string; var AItems : TArrayOfString) : boolean;
function ArrayToStr(ASeparator : string; AItems : TArrayOfString) : string;

// command line parameters parsing
function ParamSwitchExists(AName : string) : boolean;
function ParamSwitchValue(AName : string; ANth : integer = 1) : string;
function ParamSwitchValues(AName,AResultSeparator,ASwitchCharacter : string) : string;

// special functions
procedure nop;

implementation

function StrToArray(AData,ASeparator : string; var AItems : TArrayOfString) : boolean;
{*
Convert string separated by common ceparators into array of strings
Errors: Raise exception if ASeparator is empty
See also: ArrayToStr
}
var a,c : integer;
begin
  if AData = '' then
  begin
    SetLength(AItems,0);
    result := false;
    exit;
  end;
  if ASeparator = '' then
    raise Exception.Create('Separator in StrToArray cannot be empty!');
  c := 0;
  repeat
    a := pos(ASeparator,AData);
    if a=0 then
      a := Length(AData)+1;
    inc(c);
    SetLength(AItems,c);
    AItems[c-1] := copy(AData,1,a-1);
    AData := copy(AData,a+length(ASeparator),maxint);
  until AData='';
  result := c > 0;
end;

function ArrayToStr(ASeparator : string; AItems : TArrayOfString) : string;
{*
Convert array of string to string
Errors: None, unlike StrToArray, ASeparator may be empty string
See slso: StrToArray
}
var i : integer;
begin
  result := '';
  for i := 0 to high(AItems) do
  begin
    if i > 0 then
      result := result + ASeparator;
    result := result + AItems[i];
  end;
end;

function ParamSwitchExists(AName : string) : boolean;
{*
Return true if given parameter exists
Errors: It cannot distinct between value and actual switch, e.g. in -foo -bar 2, value of -foo is "-bar"
See also: ParamSwitchExists, ParamSwitchValue, ParamSwitchValues
}
var i : integer;
begin
  result := false;
  for i := 1 to ParamCount do
    if ParamStr(i)=AName then
      result := true;
end;

function ParamSwitchValue(AName : string; ANth : integer) : string;
{*
Return value of given command line parameter (-switch value), ANth (default is 1) can be specified if switch has multiple values (-size 320 200)
Errors: It cannot distinct between value and actual switch, e.g. in -foo -bar 2, value of -foo is "-bar"
See also: ParamSwitchExists, ParamSwitchValue, ParamSwitchValues
}
var i : integer;
begin
  result := '';
  for i := 1 to ParamCount-ANth do
    if ParamStr(i)=AName then
      result := ParamStr(i+ANth);
end;

function ParamSwitchValues(AName,AResultSeparator,ASwitchCharacter : string) : string;
var i,j : integer;
{*
Return multiple values of one switch, values are terminated by other switch or end of parameters
Errors: It cannot distinct between value and actual switch, e.g. in -foo -bar 2, value of -foo is "-bar"
See also: ParamSwitchExists, ParamSwitchValue, ParamSwitchValues
Example usage: program.exe -f file1.txt file2.txt file3.txt -other-switch-or-end
}
begin
  result := '';
  for i := 1 to ParamCount-1 do
    if ParamStr(i)=AName then
    begin
      for j := i to ParamCount-1 do
      begin
        if copy(ParamStr(j+1),1,1)=ASwitchCharacter then
          break;
        if result<>'' then
          result := AResultSeparator + result;
        result := result + ParamStr(j+1);
      end;
    end;
end;

procedure nop;
{*
Do nothing, It is used for conditional breakpoints,
Errors: none
Example:
if a=5 then
nop; // breakpoint here
}
begin
  // foo
end;

end.
